﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Xml;
using System.Linq;
using log4net;

namespace UPNP.IO
{
	public sealed partial class DeviceDom
	{
		private readonly ILog _log = LogManager.GetLogger(typeof(DeviceDom));

		public string SchemaId
		{
			get;
			private set;
		}

        public string SchemaNamespace
        {
            get;
            private set;
        }

	    public string ControlNamespace
	    {
            get { return "urn:schemas-upnp-org:control-1-0"; }
	    }

        public Uri RootDeviceSchemaUrl
        {
            get; 
            private set;
        }

        public Device RootDevice
		{
			get;
			private set;
		}

		/// <summary>
		/// retrieves all devices recursive
		/// </summary>
		public IList<Device> GetAllDevices()
		{
			if (this.RootDevice == null)
				throw new NotSupportedException("no root device");

			var ret = new List<Device>();

			var d = new Stack<Device>();

			d.Push(this.RootDevice);

			while (d.Count > 0)
			{
				var self = d.Pop();

				// gather device
				ret.Add(self);

				// queue children
				foreach (var c in self.ChildDevices)
					d.Push(c);
			}

			return ret.AsReadOnly();
		}

		/// <summary>
		/// retrieves all services recursive
		/// </summary>
		public IList<Service> GetAllServices()
		{
			var devs = GetAllDevices();

			var ret = new List<Service>();

			foreach (var d in devs)
			{
				ret.AddRange(d.Services);
			}

			return ret;
		}

        public IEnumerable<Exception> GetSchemaErrorsRecursive()
        {
            return this.RootDevice.GetSchemaErrorsRecursive().Distinct();
        }

	    public DeviceDom(Uri rootDeviceSchemaUrl, XmlElement rootDeviceSchemaElement)
	    {
	        Contract.Requires(rootDeviceSchemaUrl != null);
	        Contract.Requires(rootDeviceSchemaElement != null);

	        Contract.Requires(rootDeviceSchemaUrl.IsAbsoluteUri);

	        this.RootDeviceSchemaUrl = rootDeviceSchemaUrl;
	        this.SchemaNamespace = rootDeviceSchemaElement.NamespaceURI;

            this.RootDevice = new Device(
                this,
                null,
                rootDeviceSchemaElement
                );
	    }

	}
}
